# -*- coding: utf-8 -*-
 ##############################################
 ##                                            ##
 ##       Data model for Compras package        ##
 ##                                             ##
 ##                                             ##
 ##              from Basiq Series              ##
 ##           by Críptidos Digitales            ##
 ##                 GPL (c)2008                 ##
  ##                                            ##
    ##############################################

"""
"""

import sys
from decimal import Decimal
import datetime

from baseModel import *

import sqlalchemy
from sqlalchemy import desc, Date, Integer, Numeric, Text, sql

currentDate = datetime.date.today()

tiposDocumentoG = []



def agrega(data):
    print "compras.model.agrega()"

    currentDateTime = datetime.datetime.today()

    ## Proceso
    if data['pedido'] != -1:
        operacionId = getOne('operaciones_documentos', documento_id=data['pedido'])
        procesoId = getOne('proceso_operacion', operacion_id=operacionId)
        proceso = getOne('procesos', id=procesoId)

        #! FALTA ACTUALIZAR STATUS A LAS PARTIDAS DEL PEDIDO

        # pedido = getOne('documentos', id=data['pedido'])
        # operacion = getOne('operaciones', id=pedido['operacion_id'])
        # proceso = getOne('procesos', operacion_id=operacion['operacion_id'])

    else:
        # Si no hay pedido se crea un Proceso nuevo
        proceso = set('procesos', tipo=data['tipo'], fecha=currentDateTime, status=u'abierto')

    print "-- proceso :", proceso

    ## Operacion ( Entrada Inventarios )
    # Se crea despues de calcular el costoTotal

    ## Documento
    # el id de operacion se actualiza despues de crearla
    if data['pedido'] != -1:
        referencia = u'%s' % data['pedido']
    else:
        referencia = u''

    documento = set('documentos', tipo_id=data['tipoDocumento_id'], folio=data['folio'], fecha=data['fecha'], rol_id=data['rol_id'], subtotal=data['subtotal'], descuento=data['descuento'], descuentoporcentaje=data['descuentoPorcentaje'], impuesto=data['impuesto'], impuestoporcentaje=data['impuestoPorcentaje'], total=data['total'], referencia=referencia, fechaalta=currentDateTime, status=u'cerrado')
    print "-- documento :", documento

    costoTotal = Decimal("0.00")

    ## PARTIDAS
    for indexPartida, item in enumerate(data['partidas']):

        #~ producto = getOne('productos', id=item['producto_id'])
        #~ productAttributes = getAll('atributosproducto', producto_id=producto['id'])

        localAception = getAception(producto_id=item['producto_id'], rol_id=app.holder['id'])

        actual = localAception['actual']
        averageCost = localAception['costopromedio']

        ## item['costo'] no se usa
        ## item['descuento'] es cero siempre

        costo = item['precio'] * (100-item['descuento'])/100 * (100-data['descuentoPorcentaje'])/100

        averageCost = (actual * averageCost + item['cantidad'] * costo)/(actual + item['cantidad'])

        actual += item['cantidad']

        # ====== Se introduce esto para capturar compras sin actualizar precios
        if datetime.date.today() < (data['fecha'] + datetime.timedelta(30)).date():

        # ------ Tab added

            ## Revisar Precios
            if getAttribute(grupo=u'producto', nombre=u'recalcularPrecioAlComprar')['valor'] == u'1':

                # print (2), m, "Revisando cambios de precios"
                margen = Decimal(getAttribute(grupo=u'producto', nombre=u'margenDeCambio')['valor'])
                sentido = getAttribute(grupo=u'producto', nombre=u'sentidoDeCambio')['valor']

                for index, rule in enumerate(activePriceRules()):

                    priceCero = [price for price in localAception['prices'] if price['tipo_id']==rule['id']]

                    if priceCero:
                        price = priceCero[0]

                        margenNeto = ((100+localAception['margen']) * (100+price['factor1'])/100 * (100-price['factor2'])/100)-100

                        precioNuevo = localAception['costo'] * (100+Decimal(data['impuestoPorcentaje']))/100 * (100+margenNeto)/100

                        if sentido == u'+/-':
                            if precioNuevo < (price['valor'] - margen) or precioNuevo > (price['valor'] + margen):
                                set('atributosproducto', id=price['id'], valor="%s" % precioNuevo)
                                #~ actualizaAtributoProducto(id=atributo['id'], valor="%s" % precioNuevo)
                                # atributo.valor = "%s" % precioNuevo
                                # session().flush()
                                # print (), "id", atributo.
                        elif sentido == u'+':
                            if precioNuevo > (price['valor'] + margen):
                                set('atributosproducto', id=price['id'], valor="%s" % precioNuevo)
                                #~ actualizaAtributoProducto(id=atributo['id'], valor="%s" % precioNuevo)
                                # session().flush()


        ## Revisar cambios a acepciones
        aception = getOne('acepciones', producto_id=item['producto_id'], rol_id=data['rol_id'])
        modifications = {}
        if aception['costo'] != item['costo']:
            modifications['costo'] = item['costo']

        if modifications:
            setAception(**modifications)

        #~ if 'aception' in item.keys():
            #~ aceptionModify(item['aception'].pop('id'), **item['aception'])


        partida = set('partidasdocumento', documento_id=documento['documento_id'], producto_id=item['producto_id'], cantidad=item['cantidad'], costo=item['precio'], precio=item['precio'], descuento=item['descuento'], impuesto=item['impuesto'], status=u'cerrada')

        print "-- partida %s :" % indexPartida, partida


        costoTotal += item['cantidad'] * costo

    ## Operacion ( ya calculado el costoTotal )
    operacion = set('operaciones', cuenta=u"inventarios", operacion_tipo=u"entrada", fecha=data['fecha'], monto=costoTotal, status=u'cerrada')
    print "-- entrada :", operacion

    set('proceso_operacion', proceso_id=proceso['proceso_id'], operacion_id=operacion['operacion_id'])
    set('operaciones_documentos', operacion_id=operacion['operacion_id'], documento_id=documento['documento_id'])

    vencimiento = data['fecha']
    if u'30 días' in data['condiciones']:
        vencimiento = data['fecha'] + datetime.timedelta(30)
    if u'15 días' in data['condiciones']:
        vencimiento = data['fecha'] + datetime.timedelta(30)
    if u'10 días' in data['condiciones']:
        vencimiento = data['fecha'] + datetime.timedelta(30)

    ## Pago
    if data['pago']:
        operacionPago = set('operaciones', cuenta=u'caja', operacion_tipo=u'pago', fecha=data['pago']['fecha'], monto=-data['pago']['total'], status=u'cerrada')

        if data['pago']['tipo'] == u'efectivo':
            tempData = data['pago']
            tempData['subtotal'] = tempData.pop('cambio')
            tempData['status'] = u'cerrado'
            tempData['tipo'] = getAttribute(grupo='tipoDocumento', nombre=tempData.pop('tipo'))

            documentoPago = set('documentos', **tempData)

        elif data['pago']['tipo'] == u'cheque':
            tempData = data['pago']
            tempData['folio'] = tempData.pop('numero')
            tempData['referencia'] = tempData.pop('cuenta')
            tempData['status'] = u'abierto'
            tempData['tipo'] = getAttribute(grupo='tipoDocumento', nombre=tempData.pop('tipo'))

            documentoPago = set('documentos', **tempData)

        set('operaciones_documentos', operacion_id=operacionPago['operacion_id'], documento_id=documentoPago['documento_id'])

        set('procesos', id=proceso['proceso_id'], status=u'cerrado')

    else:
        # La key 'pago' existe pero es None
        operacionPago = set('operaciones', cuenta=u'por pagar', operacion_tipo=u'pago', fecha=data['fecha'], fecha2=vencimiento, monto=data['total'], status=u'abierta', comentarios=data['condiciones'])

    set('proceso_operacion', proceso_id=proceso['proceso_id'], operacion_id=operacionPago['operacion_id'])

    ## Ajuste
    if data['ajuste']:
        if data['pago']:
            cuenta = u'caja'
        else:
            cuenta = u'por pagar'

        operacionAjuste = set('operaciones', cuenta=cuenta, operacion_tipo=u'abono por descuento', fecha=data['pago']['fecha'], monto=-data['pago']['monto'], status=u'cerrada', referencia=data['pago']['referencia'])
        add('proceso_operacion', proceso_id=proceso['proceso_id'], operacion_id=operacionAjuste['operacion_id'])

        documentoAjuste = set('documentos', operacion_tipo=data['ajuste']['tipoDocumento'], folio=data['ajuste']['folio'], fecha=data['ajuste']['fecha'], rol_id=data['rol_id'], total=data['ajuste']['monto'], status=u'cerrado')
        set('operaciones_documentos', operacion_id=operacionAjuste['operacion_id'], documento_id=documentoAjuste['documento_id'])

    if data['pedido'] != -1:
        set('documentos', id=data['pedido'], status=u'cerrado')

    set('productos', id=item['producto_id'], costopromedio=averageCost, actual=actual)

    if data['folio'] == int(getAttribute(grupo=u'folioDocumento', nombre=u'compra')['valor']):
        modificaFolio(data['folio'])

    return True


def getCondicionesPago():
    registros = getAttributes(grupo=u'condicionesPago')
    return registros


def getCuentas():
    holder = app.holder
    for cuenta in holder['cuentas']:
        rol = getRol(id=int(cuenta['referencia']))
        #~ person = getPerson(id=rol['entidad_id'])
        #~ rol['person'] = person
        cuenta['bank'] = rol
    return holder['cuentas']


def getDefaultDocumentType():
    documentType = getAttribute(grupo=u'tipoDocumentoCompra', nombre=u'default')
    return documentType


def folioExists(*args):
    command = """SELECT COUNT(*) FROM documentos JOIN operaciones_documentos USING (documento_id) JOIN operaciones USING (operacion_id) WHERE documentos.folio='%s' AND documentos.rol_id=%s AND operaciones.operacion_tipo='entrada' """ % (args[0], args[1])
    query(command)

    registro = fetchOne()['count']

    if registro:
        return True
    else:
        return False


def getNextFolio():
    folio = int(getAttribute(grupo=u'folioDocumento', nombre=u'compra')['valor'])
    folio += 1
    return unicode(folio).zfill(4)


def getFormasPago():
    registros = getAttributes(grupo=u'formaPago', order=u'referencia')
    return registros


def getLines(**filtros):
    """ Filtra por referencia """
    if 'referencia' in filtros.keys():
        lines = getAttributes(grupo=u'líneaProducto', referencia=filtros['referencia'], order=u'nombre')
    else:
        lines = getAttributes(grupo=u'líneaProducto', order=u'nombre')
    return lines


def getOrders(**filters):
    typePedido = getAttribute(grupo=u'tipoDocumento', nombre=u'pedido')
    filtersText = """tipo_id = %s AND """ % typePedido['id']
    if 'rol_id' in filters.keys():
        filtersText += """rol_id = %s AND """ % filters['rol_id']
    if 'sinCompra' in filters.keys():
        filtersText += """status != 'cerrado' AND """
    query("""SELECT * FROM documentos WHERE %s """ % filtersText.rstrip("AND "))
    orders = fetchAll()
    return orders


def getPartidas(**filtros):
    partidas = getAll('partidasdocumento', **filtros)
    #~ registros = man.session().query(PartidaDocumento).filter_by(**filtros).all()
    return partidas


def getPedido(**filtros):
    if filtros.has_key('id'):
        #~ registro = man.session().query(Documento).filter(Documento.documento_id==filtros['id']).one()
        registro = getDocumento(documento_id=filtros['id'])
    elif filtros.has_key('proceso_id'):
        f=g
        registro = man.session().query(Documento).filter(Documento.tipo==u'pedido').filter(Documento.proceso_id==filtros['proceso_id']).first()
    elif filtros.has_key('sinCompra'):
        f=g
        registro = session().query(Documento).filter(Documento.tipo==u'pedido').filter(sql.func.lower(Documento.status)==u'abierto').first()
    return registro


#~ @property
def getProcessCount():
    query("""SELECT count(*) FROM procesos WHERE tipo='compra' """)
    count = fetchOne()
    return count


#~ @property
def getProductCount():
    query("""SELECT count(*) FROM productos""")
    return fetchOne()


def getPurchases(**filters):
    command = """SELECT procesos.proceso_id, procesos.status,
    array_agg(ops.operacion_id) AS operaciones_id,
    array_agg(ops.operacion_tipo) AS operaciones_tipo,
    array_agg(ops.fecha) AS operaciones_fecha,
    array_agg(ops.monto) AS operaciones_monto,
    array_agg(ops.status) AS operaciones_status
    FROM procesos
    JOIN proceso_operacion USING(proceso_id)
    JOIN (SELECT op.operacion_id, op.operacion_tipo, op.fecha, op.monto, op.status,
        array_agg(docs.documento_id) AS documentos_id,
        array_agg(docs.tipo_id) AS documentos_tipo_id,
        array_agg(docs.rol_id) AS documentos_rol_id,
        array_agg(docs.folio) AS documentos_folio,
        array_agg(docs.folio) AS documentos_fecha,
        array_agg(docs.folio) AS documentos_total
        FROM operaciones AS op JOIN operaciones_documentos USING (operacion_id) JOIN documentos AS docs USING (documento_id)
        GROUP BY op.operacion_id, op.operacion_tipo, op.fecha, op.monto, op.status
        ) AS ops
    USING (operacion_id)
    JOIN operaciones_documentos USING (operacion_id)
    JOIN documentos USING (documento_id)
    WHERE
    GROUP BY proceso_id, procesos.status, documentos.fecha
    ORDER BY documentos.fecha ASC
    LIMIT 100 """
    filtersText = ""
    for filter in filters.keys():
        if type(filters[filter]) in (str, unicode, datetime.datetime):
            filtersText += "%s='%s' AND " % (filter, filters[filter])
        elif type(filters[filter]) in (list,):
            temp = ("%s" % filters[filter]).replace("[", "(").replace("]",")")
            filtersText += "%s IN %s AND " % (filter, temp)
        else:
            filtersText += "%s=%s AND " % (filter, filters[filter])
    command = command.replace("WHERE", "WHERE %s " % filtersText.rstrip("AND "))
    #~ print command
    query(command)
    purchases = fetchAll()
    return purchases


def getSuppliers():
    supplierType = getAttribute(grupo='tipoRol', nombre='proveedor')
    query("""SELECT roles.*, e.personalidad, e.nombre, e.nombre2, e.alias, e.fechanacimiento, e.rfc, e.curp FROM roles JOIN entidades AS e ON (roles.entidad_id=e.id) WHERE tipo_id=%s ORDER BY nombre""" % supplierType['id'])
    suppliers = fetchAll()

    global __supplierCount
    __supplierCount = len(suppliers)

    return suppliers


@property
def supplierCount():
    return __supplierCount


def getTiposDocumento():
    global tiposDocumentoG
    if not tiposDocumentoG:
        tiposDocumentoG = getAttributes(grupo=u'tipoDocumento', referenciaLIKE=u'compra')
        print tiposDocumentoG
        #~ tiposDocumentoG = man.session().query(Atributo).filter(Atributo.grupo==u'tipoDocumento').filter(Atributo.referencia.like(u'%compra%')).all()
    return tiposDocumentoG


def getTiposDocumentoAjuste():
    registros = getAttributes(grupo=u'tipoDocumento', referencia=u'ajustes')
    return registros


def modifica(data):
    """ Se carga el proceso y todo se realiza sobre este registro """
    print "compras.model.modifica()"

    currentDateTime = datetime.datetime.today()

    proceso = getFullProcess(proceso_id=data['proceso_id'])

    if 'documento' in data.keys():
        documento = getDocumento(documento_id=data['documento']['documento_id'])
        set('documentos', **data['documento'])

    if 'pago' in data.keys():
        """ 1) Una operacion de pago puede servir a dos procesos diferentes
            2) Un documento NO puede servir a dos operaciones diferentes
        """

        operacionPagoZero = [x for x in proceso['operations'] if x['operacion_tipo']==u'pago']

        print "%s\n    " % operacionPagoZero

        if operacionPagoZero:
            operacionPago = operacionPagoZero[0]
            if 'documento' in data['pago'].keys():
                documentoPago = data['pago'].pop('documento')

                if 'tipo' in documentoPago.keys():
                    if documentoPago['tipo'] in [u'cheque', u'efectivo']:
                        documentoPago['tipo_id'] = getAttribute(grupo=u'tipoDocumento', nombre=documentoPago.pop('tipo'))['id']

                if 'cambio' in documentoPago.keys():
                    documentoPago['subtotal'] = documentoPago.pop('cambio')

                if 'numero' in documentoPago.keys():
                    documentoPago['folio'] = documentoPago.pop('numero')

                if 'cuenta' in documentoPago.keys():
                    documentoPago['referencia'] = documentoPago.pop('cuenta')

                documentoPago['status'] = u'pendiente'
                documentoPago['fechaalta'] = currentDateTime

                documentosPago = getDocuments(operacion_id=operacionPago['operacion_id'])

                if documentosPago:
                    documentoPago['documento_id'] = documentosPago[0]['documento_id']

                documentoPago = set('documentos', **documentoPago)

                if not documentosPago:
                    set('operaciones_documentos', operacion_id=operacionPago['operacion_id'], documento_id=documentoPago['documento_id'])

                data['pago']['status'] = u'cerrada'

            if data['pago']:
                data['pago']['operacion_id'] = operacionPago['operacion_id']

                set('operaciones', **data['pago'])

                proceso['proceso_id'] = proceso.pop('proceso_id')
                proceso['status'] = u'cerrado'

        else:
            """ 3) No existe Operacion, ya existe Documento """

            """ Este método se incluye por compatibilidad, se supone que la
                operación de pago ya debe estar capturada, sea en la cuenta
                Caja o en la cuenta Por pagar"""

            documentoPago = dameDocumento(tipo=data['pago']['tipo'], folio=data['pago']['folio'], rol_id=data['pago']['rol_id'])

            if documentoPago:
                proceso.operaciones.append(documentoPago.operacion)
                man.session().flush()
            else:
                """ 4) No existe Operacion, no existe documento """
                operacionPago = Operacion(tipo=u'pago', cuenta=u'caja', fecha=data['pago']['fecha'], monto=data['pago']['total'], status=u'cerrada')
                man.session().flush()

                banco = rol(tipo=u'banco', funcion=u'Banco', alias=data['pago']['referencia'])
                data['pago']['rol_id'] = banco.id
                documentoPago = Documento(**data['pago'])
                documentoPago.operacion_id = operacionPago.id
                man.session().flush()

                proceso.operaciones.append(operacionPago)
                man.session().flush()

    if 'ajuste' in data.keys():
        if 'document_id' in data['ajuste'].keys():   ## Puede no existir este documento
            ajuste = getDocumento(documento_id=data['ajuste'].pop('documento_id'))
            ajuste.update(**data['ajuste'])
        else:
            pago = [x for x in proceso['operations'] if x['operacion_tipo']==u'Pago'][0]

            operacionPago = set('operaciones', tipo="Abono por descuento", cuenta=pago['cuenta'], fecha=data['ajuste']['fecha'], monto=-data['ajuste']['total'], status=u'cerrada')

            #~ operacion = Operacion(tipo="Abono por descuento", cuenta=pago.cuenta, fecha=data['ajuste']['fecha'], monto=-data['ajuste']['total'], status=u'cerrada')
            #~ man.session().add(operacion)
            #~ man.session().flush()
            #~ proceso.operaciones.append(operacion)

            data['ajuste']['operacion_id'] = operacionPago['operacion_id']

            ajuste = set('documentos', **data['ajuste'])
            #~ session().add(ajuste)

    #~ man.session().commit()








def modificaFolio(folio):
    setAttribute(grupo=u'folioDocumento', nombre=u'compra', valor=folio)
    return

    try:
        # int(folio)
        registro = atributoI(grupo=u'folioDocumento', nombre=u'compra', valor=folio)
        # registro.valor = unicode(folio)
        # session().add(registro)
        # session().commit()
    except:
        pass


def partidas(**filters):
    partidas = getAll('partidasdocumento', **filters)
    return partidas


def rangosPrecio():
    rangos = getAttributes(grupo=u'rangoPrecioProducto', order=u'referencia')
    return rangos


def activePriceRules():
    data = getAttributes(grupo='rangoPrecioProducto', order='referencia')
    active = []
    for rule in data:
        if rule['referencia'][1] == 'a':
            active.append(rule)
    return active














def actualizaAtributoProducto(**datos):
    anterior = atributoProductoI(id=datos['id'])
    nuevo = AtributoProducto(producto_id=anterior.producto_id, nombre=anterior.nombre, valor=anterior.valor, factor1=anterior.factor1, factor2=anterior.factor2, referencia=anterior.referencia, usuario=anterior.usuario, status=u'obsoleto', fechaalta=anterior.fechaalta, fechabaja=datetime.datetime.today())
    anterior.fechaalta = datetime.datetime.today()
    if 'valor' in datos.keys():
        anterior.valor = datos['valor']


def atributoProductoI(**filtros):
    registro = man.session().query(AtributoProducto).filter(AtributoProducto.id==filtros['id']).one()
    return registro


def consolidaEntradas(partidas):
    for registro in partidas:
        producto = dameProducto(id=registro.producto_id)
        if producto.actual:
            producto.actual += registro.cantidad
        else:
            producto.actual = registro.cantidad
    session().commit()

"""
def acepcionExiste(**filtros):
    try:
        if 'codigo' in filtros.keys():
            registro = session().query(Acepcion).filter(Acepcion.codigo==unicode(filtros['codigo'])).filter(Acepcion.rol_id==filtros['rol_id']).filter(Acepcion.status==u'actual').one()
        else:

            registro = session().query(Acepcion).filter(Acepcion.producto_id==filtros['producto_id']).filter(Acepcion.rol_id==filtros['rol_id']).filter(Acepcion.status==u'actual').one()
        return registro
    except:
        return None


def dameAcepcion(**filtros):
    # try:
        if filtros.has_key('id'):
            registro = man.session().query(Acepcion).filter(Acepcion.id==filtros['id']).one()
        elif 'producto_id' in filtros.keys():
            registro = man.session().query(Acepcion).filter(Acepcion.producto_id==filtros['producto_id']).filter(Acepcion.rol_id==filtros['rol_id']).filter(Acepcion.status==u'actual').one()
        else:
            registro = session().query(Acepcion).filter(Acepcion.codigo==unicode(filtros['codigo'])).filter(Acepcion.rol_id==filtros['rol_id']).filter(Acepcion.status==u'actual').one()
        return registro
    # except:
        # raise Exception("\ncompras.manejador.dameAcepcion\nfiltros:%s\n%s" % (filtros, sys.exc_info()))
"""

def dameAcepciones(**filtros):
    if 'status' not in filtros.keys():
        filtros['status'] = u'actual'

    if 'linea' in filtros.keys():
        #! Esto debe ser hecho para linea
        clasificacion = filtros.pop('clasificacion')
        if 'nombre' in filtros.keys():
            registros = session().query(Acepcion).filter(Acepcion.rol_id==filtros['rol_id']).filter(sql.func.lower(Acepcion.nombre).like("%s%%" % filtros['nombre'])).filter(Acepcion.status==filtros['status']).filter(producto.clasificacion==clasificacion).order_by(Acepcion.nombre).all()
        elif 'codigo' in filtros.keys():
            registros = session().query(Acepcion).filter(Acepcion.rol_id==filtros['rol_id']).filter(sql.func.lower(Acepcion.codigo).like("%s%%" % filtros['codigo'])).filter(Acepcion.status==filtros['status']).filter(Producto.clasificacion==clasificacion).order_by(Acepcion.codigo).all()

    else:
        if 'nombre' in filtros.keys():
            registros = man.session().query(Acepcion).filter(Acepcion.rol_id==filtros['rol_id']).filter(sql.func.lower(Acepcion.nombre).like("%s%%" % filtros['nombre'])).filter(Acepcion.status==filtros['status']).join(Producto).join((Atributo, Atributo.id==Producto.tipo_id)).filter(Atributo.nombre!=u'Servicio').order_by(Acepcion.nombre).all()
        elif 'codigo' in filtros.keys():
            registros = session().query(Acepcion).filter(Acepcion.rol_id==filtros['rol_id']).filter(sql.func.lower(Acepcion.codigo).like("%s%%" % filtros['codigo'].lower())).filter(Acepcion.status==filtros['status']).join(Producto).join((Atributo, Atributo.id==Producto.tipo_id)).filter(Atributo.nombre!=u'Servicio').order_by(Acepcion.codigo).all()

    return registros


def dameBancos():
    f=g
    #! obsoleto, use rol() con tipo='banco'
    registros = session().query(Atributo).filter(Atributo.propietario==u'bancos').filter(Atributo.nombre==u'nombre').order_by(Atributo.valor).all()
    registros = [x.valor for x in registros]
    return registros


def documentoI(**filtros):
    if 'id' in filtros.keys():
        registro = man.session().query(Documento).filter(Documento.documento_id==filtros['id']).one()
    elif 'tipo' in filtros.keys():
        tipo = man.session().query(Atributo).filter(Atributo.grupo==u'tipoDocumento').filter(Atributo.nombre==filtros['tipo']).one()

        operaciones = man.session().query(Proceso).filter(Proceso.proceso_id==filtros['proceso_id']).one().operaciones

        registro = man.session().query(Documento).filter(Documento.tipo_id==tipo.id).filter(Documento.operacion_id.in_([x.id for x in operaciones])).one()
    else:
        registro = man.session().query(Documento).filter_by(**filtros).first()

    return registro


def dameDocumentos(**filtros):
    if filtros:
        if filtros.has_key('rol_id'):
            if filtros.has_key('status'):
                registros = session().query(Documento).filter(Documento.tipo.in_([u'factura', u'remisión'])).join(Proceso).filter(sql.func.lower(Proceso.tipo)==u'compra').filter(Documento.rol_id==filtros['rol_id']).filter(Proceso.status.in_(filtros['status'])).order_by(Documento.fecha.desc()).all()
            else:
                registros = session().query(Documento).filter(Documento.tipo.in_([u'factura', u'remisión'])).join(Proceso).filter(sql.func.lower(Proceso.tipo)==u'compra').filter(Documento.rol_id==filtros['rol_id']).order_by(Documento.fecha.desc()).all()
        # elif filtros.has_key('proceso_id'):
            # registros = session().query(Documento).join(Operacion).filter(Operacion.proceso_id==filtros['proceso_id']).order_by(Documento.fecha.desc()).all()
        else:
            if filtros.has_key('status'):
                registros = session().query(Documento).filter(Documento.tipo.in_([u'factura', u'remisión'])).join(Proceso).filter(sql.func.lower(Proceso.tipo)==u'compra').filter(Proceso.status.in_(filtros['status'])).order_by(Documento.fecha.desc()).all()
            else:
                registros = session().query(Documento).filter_by(**filtros).order_by(Documento.fecha.desc()).all()
    else:
        registros = session().query(Documento).filter(Documento.tipo.in_([u'factura', u'remisión'])).join(Proceso).filter(sql.func.lower(Proceso.tipo)==u'compra').order_by(Documento.fecha.desc()).all()
    return registros


def operacionI(**filtros):
    if 'id' in filtros.keys():
        registro = man.session().query(Operacion).filter(Operacion.operacion_id==filtros['id']).one()
    elif 'cuenta' in filtros.keys():
        registro = man.session().query(Operacion).filter(Operacion.cuenta==filtros['cuenta']).filter(Operacion.documento_id==filtros['documento_id']).first()
    elif 'proceso_id' in filtros.keys():
        proceso = man.session().query(Proceso).filter(Proceso.proceso_id==filtros['proceso_id']).one()
        registroZero = [x for x in proceso.operaciones if x.tipo==filtros['tipo']]
        if registroZero:
            registro = registroZero[0]
    else:
        registro = man.session().query(Operacion).filter_by(**filtros).one()
    return registro


def dameOperaciones(**filtros):
    if 'proceso_id' in filtros.keys():
        links = [x[0] for x in man.session().execute("SELECT operacion_id FROM proceso_operacion WHERE proceso_id=%s" % filtros['proceso_id'])]
        # links = session().execute("SELECT operacion_id FROM proceso_operacion WHERE proceso_id=%s" % filtros['proceso_id'])
        registros = man.session().query(Operacion).filter(Operacion.operacion_id.in_(links)).all()
        # registros = session().query(Operacion).filter(Operacion.procesos.any(Proceso.id==filtros['proceso_id'])).all()
    else:
        registros = man.session().query(Operacion).filter_by(**filtros).all()
    return registros


def damePagos(**filtros):
    registro = man.session().query(Operacion).filter(Operacion.cuenta==u'pagos').filter(Operacion.documento_id==filtros['documento_id']).all()
    return registro





def damePedido(**filtros):
    if filtros.has_key('id'):
        registro = man.session().query(Documento).filter(Documento.documento_id==filtros['id']).one()
    elif filtros.has_key('proceso_id'):
        f=g
        registro = man.session().query(Documento).filter(Documento.tipo==u'pedido').filter(Documento.proceso_id==filtros['proceso_id']).first()
    elif filtros.has_key('sinCompra'):
        f=g
        registro = session().query(Documento).filter(Documento.tipo==u'pedido').filter(sql.func.lower(Documento.status)==u'abierto').first()
    return registro


def procesoI(**filtros):
    m = "compras.manejador.procesoI()"
    if 'id' in filtros.keys():
        registro = man.session().query(Proceso).filter(Proceso.proceso_id==filtros['id']).one()
    elif 'documento_id' in filtros.keys():
        documento = documentoI(id=filtros['documento_id'])
        registro = man.session().query(Proceso).filter(Proceso.operaciones.any(id=documento.operacion_id)).one()
    else:
        registro = man.session().query(Proceso).filter(Proceso.operaciones.any(id=filtros['operacion_id'])).one()
    return registro

'''
def dameProcesos(**filtros):
    #! status es de documento, ¿Para procesos es igual?
    if 'status' in filtros.keys():
        if 'rol_id' in filtros.keys():
            registros = session().query(Proceso).filter(Proceso.tipo.in_(filtros['tipo'])).filter(Proceso.status==filtros['status']).filter(Proceso.operaciones.any(Operacion.documentos.any(Documento.rol_id==filtros['rol_id']))).order_by(Proceso.fecha).all()
        else:
            registros = man.session().query(Proceso).filter(Proceso.tipo==filtros['tipo']).filter(Proceso.status==filtros['status']).order_by(Proceso.fecha).all()
    else:
        if 'rol_id' in filtros.keys():
            if 'tipo' in filtros.keys():
                registros = man.session().query(Proceso).filter(Proceso.tipo.in_(filtros['tipo'])).filter(Proceso.operaciones.any(Operacion.documentos.any(Documento.rol_id==filtros['rol_id']))).order_by(Proceso.fecha).all()
            else:
                registros = man.session().query(Proceso).filter(Proceso.tipo.in_([u'compra', 'gasto'])).filter(Proceso.operaciones.any(Operacion.documentos.any(Documento.rol_id==filtros['rol_id']))).order_by(Proceso.fecha).all()

            # registros = session().query(Proceso).filter(Proceso.tipo==u'Compra').filter(Proceso.operaciones.rol_id==filtros['rol_id']).order_by(Proceso.fecha).all()
        else:
            if 'tipo' in filtros.keys():
                registros = man.session().query(Proceso).filter(Proceso.tipo.in_(filtros['tipo'])).order_by(Proceso.fecha).all()
            else:
                registros = man.session().query(Proceso).filter(Proceso.tipo.in_([u'compra', u'gasto'])).order_by(Proceso.fecha).all()
            # registros = man.session().query(Proceso).filter(Proceso.tipo==u'compra').filter(Proceso.operaciones.any(Operacion.documentos.any(Documento.tipo.nombre.in_(['factura'])))).order_by(Documento.fecha).all()
    return registros
'''

def dameProveedores():
    f=g
    tipo_id = atributoI(grupo=u'tipoRol', nombre=u'proveedor').id
    registros = man.session().query(Rol).filter(Rol.tipo_id==tipo_id).join(Entidad).order_by(Entidad.nombre).all()
    return registros


def dameRol(**filtros):
    f=g
    #! obsoleto, use rol()
    if 'id' in filtros.keys():
        registro = session().query(Rol).filter(Rol.id==filtros['id']).one()
    elif 'tipo' in filtros.keys():
        registro = session().query(Rol).filter(Rol.tipo==filtros['tipo']).one()
    return registro


def elimina(**filtros):
    registro = session().query(Documento).filter(Documento.documento_id==filtros['id']).one()
    session().delete(registro)
    session().commit()



def operaciones_documentos(operacion_id, documento_id):
    operacion = operacionI(id=operacion_id)
    documento = dameDocumento(id=documento_id)
    operacion.documentos.append(documento)
    man.session().add(operacion)
    man.session().commit()


def operacionExiste(**filtros):
    f=g
    registro = session().query(Operacion).filter(Operacion.cuenta==filtros['cuenta']).filter(Operacion.referencia==filtros['referencia']).first()
    return registro


def pagoExiste(**filtros):
    try:
        f=g
        registro = session().query(Pago).filter(Pago.documento_id==filtros['documento_id']).one()
        return True
    except:
        return False


def totalDeProductos():
    return man.session().query(sql.func.count(Producto.id)).one()[0]



def inicializaX():
    backend.metadata.create_all(engine)
    # try:
        # version = int(atributoI(grupo=u'pago', nombre=u'versionBasedatos').valor)
    # except:
        # print "Inicializando Base de datos de Pagos"


        # atributoI(grupo=u'pago', nombre=u'versionBasedatos', valor=u'3')
        # version = 3
        # session().commit()





if __name__ == "__main__":
    print "testing..."



"""
Lógica para el manejo de acepciones [20 Abr 2010]

La captura de acepciones evitará modificar datos ya existentes.

Se llevarán dos registros de las acepciones capturadas, uno para las capturadas por acepción local, y otro para las capturadas por acepción de proveedor.

Las partidas del documento guardan sólo las referencias a las acepciones del proveedor, no los textos, por lo que no se podrán utilizar acepciones temporales o por evento.

Si un artículo no cuenta con una acepción del proveedor, la rutina de registro la creará a partir de los textos recibidos, esta es la única modificación que se podrá realizar.

En los widgets de captura, la selección de un artículo se puede realizar mediante cualquier acepción registrada, cualquiera.

Independientemente del origen que se haya seleccionado, se identifica el producto y se guardan los textos de la acepción local.

En caso de que se haya seleccionado un proveedor para el documento, se busca la acepción para ese proveedor, si existe, se guarda, y es la que se muestra, si no existe, se guarda los textos de la acepción que se utilizó para identificar el artículo, y serán los que se usarán para crear la acepción para el proveedor seleccionado.

#!
Si no existe acepción para un artículo capturado, se deberá permitir la modificación de los textos, para que se cree la acepción con los textos adecuados.


"""